package com.csair.seam.infrastructure.utils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JwtUtil {
	private final static String JWT_ISSUER = "SEAM";
	
	private final static String  JWT_SECRET = "secret";
	
	private final static String  JWT_ALG_KEY = "alg";
	private final static String  JWT_ALG_VALUE = "HS256";
	
	private final static String  JWT_TYP_KEY = "typ";
	private final static String  JWT_TYP_VALUE = "JWT";
	
	private final static String HEADER_JWT_TOKEN_KEY = "X-Jwt-Token";
	
	
	/**
	 * @description 创建不携带自定义信息的 token
	 */
	public static String createToken() {
		//1.构建头部信息
		Map<String, Object> map = new HashMap<>();
		map.put(JWT_ALG_KEY, JWT_ALG_VALUE);
		map.put(JWT_TYP_KEY, JWT_TYP_VALUE);
		
		//2.构建密钥信息
		Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
		
		//3.通过定义注册和自定义声明 并组合头部信息和密钥信息生成jwt token
		Date nowDate = new Date();
		Date expireDate = DateUtils.addHours(nowDate, 2);//2小时过期
		String token = JWT.create()
			    .withHeader(map)// 设置头部信息 Header 
			    .withIssuer(JWT_ISSUER)//设置 载荷 签名是有谁生成 例如 服务器
			    .withIssuedAt(nowDate) //设置 载荷 生成签名的时间
			    .withExpiresAt(expireDate)//设置 载荷 签名过期的时间
			    .sign(algorithm);//签名 Signature
		return token;
	}
	
	/**
	 * @description 生成携带自定义信息 JWT token
	 */
	public static String createTokenwithClaim(String account) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(JWT_ALG_KEY, JWT_ALG_VALUE);
		map.put(JWT_TYP_KEY, JWT_TYP_VALUE);
		
		Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
		
		Date nowDate = new Date();
//		Date expireDate = DateUtils.addHours(nowDate, 2);//2小时过期
		String token = JWT.create().withHeader(map)
				.withIssuer(JWT_ISSUER)// 签名是有谁生成 例如 服务器
				.withClaim("account", account)
				.withIssuedAt(nowDate) // 生成签名的时间
//				.withExpiresAt(expireDate)// 签名过期的时间
				.sign(algorithm);
		return token;
	}
	
	/**
	 * @description 解密JWT Token
	 * @param token
	 * @return
	 */
	private static DecodedJWT decodeJwt(String token) {
		Algorithm algorithm = Algorithm.HMAC256(JWT_SECRET);
		JWTVerifier verifier = JWT.require(algorithm).withIssuer(JWT_ISSUER).build(); // Reusable verifier instance
		return verifier.verify(token);
	}
	
	/**
	 * @description 验证 JWT Token
	 */
	public static JSONObject verifyToken(HttpServletRequest request) {
		String jwtToken = request.getHeader(HEADER_JWT_TOKEN_KEY);
		JSONObject jsonObject = new JSONObject();
		if(StringUtils.isEmpty(jwtToken)) {
			jsonObject.put("code", 1);
			jsonObject.put("msg", "token is null");
		}
		try {
			decodeJwt(jwtToken);
			jsonObject.put("code", 0);
		}catch (JWTVerificationException e) {
			log.error(e.getMessage(),e);
			jsonObject.put("code", 1);
			jsonObject.put("msg", e.getMessage());
		}
		return jsonObject;
	}
	
	public static String getAccount(HttpServletRequest request) {
		String jwtToken = request.getHeader(HEADER_JWT_TOKEN_KEY);
		DecodedJWT decodedJWT = decodeJwt(jwtToken);
		return decodedJWT.getClaim("account").asString();
	}
	
}
